#include "BaseDeConocimientosManager.h"

using namespace basedeconocimientos;

BaseDeConocimientosManager::BaseDeConocimientosManager(void)
{
	this->manejadorDeArchivos = new ManejadorDeArchivos();
	this->keywordsRepository = new KeywordsRepository();
};

/**
* Elaboro una estadistica con el peso de 'prescindibilidad' las materias incluidas en el archivo
* comentarios. Aquellas que tengan un peso < 0 son prescindibles. Se devolvera la lista ordenado de mayor a 
* menor prescindibilidad. Para esta restriccion, solo importa el codigo de materia.
*/
vector<DiaCatedraMateriaDTO> BaseDeConocimientosManager::ObtenerMateriasPrescindibles()
{
	list<string> keywordsPrescindibilidad = this->keywordsRepository->ObtenerKeywordsPrescindibilidad();
	list<string> keywordsImprescindibilidad = this->keywordsRepository->ObtenerKeywordsImprescindibilidad();
	return this->ObtenerMaterias(keywordsPrescindibilidad, keywordsImprescindibilidad);
};

vector<DiaCatedraMateriaDTO> BaseDeConocimientosManager::ObtenerMateriasDificultosas()
{
	list<string> keywordsMateriaDificultosa = this->keywordsRepository->ObtenerKeywordsMateriaDificultosa();
	list<string> keywordsMateriaAccesible = this->keywordsRepository->ObtenerKeywordsMateriaAccesible();
	return this->ObtenerMaterias(keywordsMateriaDificultosa, keywordsMateriaAccesible);
};

vector<DiaCatedraMateriaDTO> BaseDeConocimientosManager::ObtenerMateriasSinChequeoDeAsistencia()
{
	list<string> keywordsSinChequeoAsistencia = this->keywordsRepository->ObtenerKeywordsChequeoAsistencia();
	list<string> keywordsConChequeoAsistencia = this->keywordsRepository->ObtenerKeywordsNoChequeoAsistencia();
	return this->ObtenerMaterias(keywordsConChequeoAsistencia, keywordsSinChequeoAsistencia);
};


vector<DiaCatedraMateriaDTO> BaseDeConocimientosManager::ObtenerMaterias(list<string> &keywordsQueSuman, 
			list<string> &keywordsQueRestan)
{
	vector<DiaCatedraMateriaDTO> materiasPrescindibles;
	map<string, DiaCatedraMateriaDTO> matrizMaterias;
	fstream archivo = this->manejadorDeArchivos->Abrir(COMENTARIOS_MATERIAS_PATH);
	string codigoMateriaActual, codigoCatedraActual;
	while(!archivo.eof())
	{
		string linea;
		getline(archivo, linea, '\n');
		if(this->EmpiezaInformacionDeUnaMateria(linea))
		{
			codigoMateriaActual = this->ObtenerCodigoMateria(linea);
			codigoCatedraActual = this->ObtenerCodigoCatedra(linea);
			if(matrizMaterias.find(this->ObtenerCodigoMateria(linea)) == matrizMaterias.end())
			{
				DiaCatedraMateriaDTO diaCatedraMateria;
				diaCatedraMateria.codigoMateria = codigoMateriaActual;
				diaCatedraMateria.codigoCatedra = codigoCatedraActual;
				diaCatedraMateria.peso = 0;
				matrizMaterias[diaCatedraMateria.codigoMateria] = diaCatedraMateria;
			}
		} else
		{
			this->EvaluarLineaParaMateria(&matrizMaterias, keywordsQueSuman, keywordsQueRestan, 
				linea, codigoMateriaActual);
		}
	}
	for(map<string, DiaCatedraMateriaDTO>::iterator iterador = matrizMaterias.begin(); 
		iterador != matrizMaterias.end(); ++iterador) 
	{
		DiaCatedraMateriaDTO materia = matrizMaterias[iterador->first];
		if(materia.peso > 0)
			materiasPrescindibles.push_back(materia);
	}
	std::sort(materiasPrescindibles.begin(), materiasPrescindibles.end(), ComparadorDTO());
	return materiasPrescindibles;
};

	void BaseDeConocimientosManager::EvaluarLineaParaMateria(map<string,DiaCatedraMateriaDTO> *matrizMaterias, list<string> &keywordsQueSuman, 
			list<string> &keywordsQueRestan, string linea, string codigoMateriaActual)
{
	list<string>::iterator itQueSuman;
	for(itQueSuman = keywordsQueSuman.begin(); itQueSuman != keywordsQueSuman.end(); itQueSuman++ )
	{
		string keyQueSumaCaso1 = " " + *itQueSuman + " ";
		string keyQueSumaCaso2 = " " + *itQueSuman + ",";
		string keyQueSumaCaso3 = " " + *itQueSuman + ".";
		if(linea.find(keyQueSumaCaso1) != string::npos || linea.find(keyQueSumaCaso2) != string::npos || linea.find(keyQueSumaCaso3) != string::npos)
		{
			DiaCatedraMateriaDTO materia = (*matrizMaterias)[codigoMateriaActual];
			if((linea.find("no" + keyQueSumaCaso1) == string::npos && linea.find("no es" + keyQueSumaCaso1) == string::npos) &&
			   (linea.find("no" + keyQueSumaCaso2) == string::npos && linea.find("no es" + keyQueSumaCaso2) == string::npos) &&
			   (linea.find("no" + keyQueSumaCaso3) == string::npos && linea.find("no es" + keyQueSumaCaso3) == string::npos))
			{
				materia.peso++;
			} else {
				materia.peso--;
			}
			(*matrizMaterias)[codigoMateriaActual] = materia;
		}
	}

	list<string>::iterator itQueRestan;
	for(itQueRestan = keywordsQueRestan.begin(); itQueRestan != keywordsQueRestan.end(); itQueRestan++ )
	{
		string keyQueRestaCaso1 = " " + *itQueRestan + " ";
		string keyQueRestaCaso2 = " " + *itQueRestan + ",";
		string keyQueRestaCaso3 = " " + *itQueRestan + ".";
		if(linea.find(keyQueRestaCaso1) != string::npos || linea.find(keyQueRestaCaso2) != string::npos || linea.find(keyQueRestaCaso3) != string::npos)
		{
			DiaCatedraMateriaDTO materia = (*matrizMaterias)[codigoMateriaActual];
			if((linea.find("no" + keyQueRestaCaso1) == string::npos && linea.find("no es" + keyQueRestaCaso1) == string::npos) &&
			   (linea.find("no" + keyQueRestaCaso2) == string::npos && linea.find("no es" + keyQueRestaCaso2) == string::npos) &&
			   (linea.find("no" + keyQueRestaCaso3) == string::npos && linea.find("no es" + keyQueRestaCaso3) == string::npos))
			{
				materia.peso--;
			} else {
				materia.peso++;
			}
			(*matrizMaterias)[codigoMateriaActual] = materia;
		}
	}
};

bool BaseDeConocimientosManager::EmpiezaInformacionDeUnaMateria(string linea)
{
	bool tieneUnSeparador = count(linea.begin(), linea.end(), '_') == 1;
	bool terminaConDosPuntos = linea.length() > 0 && linea[linea.length() - 1] == ':';
	return  tieneUnSeparador && terminaConDosPuntos;	
};

string BaseDeConocimientosManager::ObtenerCodigoMateria(string linea)
{
	return linea.substr(0, linea.find('_', 0));
};

string BaseDeConocimientosManager::ObtenerCodigoCatedra(string linea)
{
	int posInicial = linea.find('_', 0) + 1;
	int longitud = linea.length() - posInicial - 1;
	return linea.substr(posInicial, longitud);
};
